package org.lc.cmd.impl.bridge;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.jline.utils.AttributedString;
import org.lc.cmd.CmdDataBridge;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

@Slf4j
public class HttpServerBridge implements CmdDataBridge {
    @Override
    public void sendCmdLine(String line) {
        throw new UnsupportedOperationException("服务端无需实现");
    }

    @Override
    public String readLine(String prompt) {
        return Optional.ofNullable(sendSync(new PollModel(PollModel.PollType.READ_LINE, prompt)))
                .map(PollModel::getData).orElse(null);
    }

    @Override
    public void write(AttributedString str, boolean above) {
        WriteModel model = new WriteModel(str, above);
        sendSync(new PollModel(PollModel.PollType.WRITE, JSON.toJSONString(model)));
    }

    @Override
    public void closeClient() {
        sendAsync(new PollModel(PollModel.PollType.CLOSE_CLIENT, null));
    }

    @Override
    public void closeServer() {
        throw new UnsupportedOperationException("服务端无需实现");
    }

    private PollModel sendSync(PollModel request) {
        HttpServerController server = HttpServerController.INSTANCE;
        try {
            String uuid = UUID.randomUUID().toString();
            request.setId(uuid);
            CompletableFuture<PollModel> future = new CompletableFuture<>();
            server.waitPollBackMap.put(uuid, future::complete);
            server.queue.put(request);
            future.get();
        } catch (InterruptedException e) {
            log.warn("发送消息失败: {}", request, e);
        } catch (ExecutionException e) {
            log.warn("接收消息失败: 发送消息：{}", request, e);
        }
        return null;
    }

    private void sendAsync(PollModel request) {
        try {
            HttpServerController.INSTANCE.queue.put(request);
        } catch (InterruptedException e) {
            log.warn("发送消息失败: {}", request, e);
        }
    }

    @RequestMapping("/cmd")  // TODO 多客户端连接同一个服务端
    @RestController
    public static class HttpServerController {
        private static HttpServerController INSTANCE;

        public HttpServerController() {
            INSTANCE = this;
        }

        private final BlockingQueue<PollModel> queue = new LinkedBlockingQueue<>();

        private final ConcurrentMap<String, Consumer<PollModel>> waitPollBackMap = new ConcurrentHashMap<>();

        @RequestMapping("/connect")
        public String connect() {
            return "OK";
        }

        @RequestMapping("/execute")
        public void execute(String line) {
            System.out.println("执行命令：" + line);
        }

        @RequestMapping("/close_server")
        public void closeServer() {
            log.info("客户端通知关闭服务端");
            System.exit(0);
        }

        /**
         * 轮询
         *
         * @return 服务端向客户端推送的"事件"
         */
        @RequestMapping("/poll")
        public PollModel poll() {
            try {
                return queue.poll(1, TimeUnit.HOURS);
            } catch (InterruptedException e) {
                return null;
            }
        }

        /**
         * 轮询回调
         *
         * @param pollModel 轮询回调,uuid与轮询匹配
         */
        @RequestMapping("/poll-back")
        public void pollBack(PollModel pollModel) {
            Consumer<PollModel> consumer = waitPollBackMap.remove(pollModel.getId());
            if (consumer != null) {
                consumer.accept(pollModel);
            }
        }
    }
}
